import { getStoredFileHandle, openDB, storeFileHandle } from '@/lib/indexedDb';
import { getAllFDirectoryHandleByDirectoryHandle } from '@/lib/utils';
import { name } from '@/package.json';
import { useGigaStore } from '@/store/giga';
import { Draft, isDraft, original } from 'immer';
import { toast } from 'sonner';
import { create } from 'zustand';
import { redux } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';

export const key = 'giga-not-persist';

export interface AvailableTaskInfo {
  id: string;
  skuIdInfo: string;
  categoryName: string;
}

export interface AvailableTask {
  handleTask: () => Promise<void>;
  taskInfo: AvailableTaskInfo;
}

export interface QueueItem {
  task: AvailableTask;
  resolve?: (result: any) => void;
  reject?: (error: any) => void;
}

function isRepeatAvailableTask(total: QueueItem[], newTaskItem: AvailableTask) {
  const { id } = newTaskItem.taskInfo;
  // 货号和操作类型相同时才认为是重复任务
  return total.some((queueItem) => queueItem.task.taskInfo.id === id);
}

export type CategoryTree = Record<string, string[]>;

export async function updateCateyoryTree(gigaRootDirectoryHandle: FileSystemDirectoryHandle) {
  const categoryTree = {} as CategoryTree;
  const categoryDirectoryHandles =
    await getAllFDirectoryHandleByDirectoryHandle(gigaRootDirectoryHandle);
  for (const categoryDirectoryHandle of categoryDirectoryHandles) {
    categoryTree[categoryDirectoryHandle.name] = (
      await getAllFDirectoryHandleByDirectoryHandle(categoryDirectoryHandle)
    ).map((handle) => handle.name);
  }
  useGigaNotPersisStore.dispatch({
    type: 'update',
    update(draftState) {
      draftState.categoryTree = categoryTree;
    },
  });
  // console.log(categoryTree);
}

function processQueue(state: Draft<State>, taskConcurrencyLimit: number, isStopByError: boolean) {
  const availableConcurrent = state.availableConcurrent;
  if (
    availableConcurrent.active.length >= taskConcurrencyLimit ||
    availableConcurrent.queue.length === 0 ||
    availableConcurrent.isStop
  )
    return;

  // 从队列中取出下一个任务
  const nextQueueItem = availableConcurrent.queue.shift();
  // console.log(nextQueueItem);
  const originalQueueItem = isDraft(nextQueueItem) ? original(nextQueueItem) : nextQueueItem;
  let successOriginalQueueItem: QueueItem | null = null;
  let failOriginalQueueItem: QueueItem | null = null;
  if (nextQueueItem) {
    availableConcurrent.active.push(originalQueueItem!);
    const nextQueueId = nextQueueItem.task.taskInfo.id;
    // 执行任务
    const taskPromise = nextQueueItem.task.handleTask();
    taskPromise
      .then((res) => {
        if (originalQueueItem && originalQueueItem.resolve) {
          originalQueueItem.resolve({
            errorCode: 0,
          });
        }
        successOriginalQueueItem = originalQueueItem!;
      })
      .catch((error) => {
        if (originalQueueItem && originalQueueItem.resolve) {
          originalQueueItem.resolve({
            errorCode: 1,
            errorMessage: error.message,
          });
        }
        failOriginalQueueItem = originalQueueItem!;
      })
      .finally(() => {
        // console.log(nextQueueItem);
        useGigaNotPersisStore.dispatch({
          type: 'update',
          update(draftState) {
            draftState.availableConcurrent.active = draftState.availableConcurrent.active.filter(
              (queueItem) => queueItem.task.taskInfo.id !== nextQueueId,
            );
            // draftState.availableConcurrent.completed.push(originalQueueItem!);
            successOriginalQueueItem &&
              draftState.availableConcurrent.success.push(successOriginalQueueItem);
            if (failOriginalQueueItem) {
              draftState.availableConcurrent.fail.push(failOriginalQueueItem);
              useGigaStore.dispatch({
                type: 'update',
                update(draftState) {
                  draftState.historyErrorAvailableTasks.push(failOriginalQueueItem!.task.taskInfo);
                },
              });
            }
            if (failOriginalQueueItem && isStopByError) {
              draftState.availableConcurrent.isStop = true;
            }
            processQueue(draftState, taskConcurrencyLimit, isStopByError); // 处理下一个任务
          },
        });
      });
  }
}

const defaultState: State = {
  gigaRootDirectoryHandle: null,
  categoryTree: {},
  currentAvailableCategoryName: '',
  selectedAvailableCategoryNames: [],
  availableConcurrent: {
    queue: [],
    active: [],
    total: [],
    // completed: [],
    success: [],
    fail: [],
    isStop: false,
    currentCategoryName: '',
  },
};

interface State {
  gigaRootDirectoryHandle: FileSystemDirectoryHandle | null;
  categoryTree: CategoryTree;
  currentAvailableCategoryName: string;
  selectedAvailableCategoryNames: string[];
  availableConcurrent: {
    queue: QueueItem[];
    active: QueueItem[];
    total: QueueItem[];
    // completed: QueueItem[];
    success: QueueItem[];
    fail: QueueItem[];
    isStop: boolean;
    currentCategoryName: string;
  };
}

type Actions =
  | {
      type: 'reset';
    }
  | {
      type: 'update';
      update: (draftState: Draft<State>) => void;
    }
  | {
      type: 'clearAvailableQueue';
    }
  | {
      type: 'clearAllQueue';
    }
  | {
      type: 'stopAvailableCollect';
    }
  | {
      type: 'resumeAvailableCollect';
    }
  | {
      type: 'resumeAvailableCollectWithError';
    }
  | {
      type: 'enqueueTask';
      task: AvailableTask;
      resolve: (result: any) => void;
      reject: (error: any) => void;
    };

const reducer = (state: Draft<State>, action: Actions) => {
  if (action.type === 'reset') {
    return defaultState;
  }
  if (action.type === 'update') {
    const update = action.update;
    update(state);
  }
  if (action.type === 'clearAvailableQueue') {
    const availableConcurrent = state.availableConcurrent;
    // 在 totalTask 队列中移除 queue 相关的任务
    availableConcurrent.total = availableConcurrent.total.filter((item) => {
      return !availableConcurrent.queue.some(
        (task) => task.task.taskInfo.id === item.task.taskInfo.id,
      );
    });
    availableConcurrent.queue = [];
  }
  if (action.type === 'clearAllQueue') {
    const availableConcurrent = state.availableConcurrent;
    availableConcurrent.active = [];
    availableConcurrent.fail = [];
    availableConcurrent.success = [];
    availableConcurrent.queue = [];
    availableConcurrent.total = [];
  }
  if (action.type === 'stopAvailableCollect') {
    state.availableConcurrent.isStop = true;
  }
  if (action.type === 'resumeAvailableCollect') {
    const availableSettings = useGigaStore.getState().availableSettings;
    state.availableConcurrent.isStop = false;
    const count = availableSettings.taskConcurrencyLimit - state.availableConcurrent.active.length;
    for (let i = 0; i < count; i++) {
      processQueue(state, availableSettings.taskConcurrencyLimit, availableSettings.isStopByError);
    }
  }
  if (action.type === 'resumeAvailableCollectWithError') {
    const availableConcurrent = state.availableConcurrent;
    const availableSettings = useGigaStore.getState().availableSettings;
    // 从错误队列中放进待处理队列
    availableConcurrent.queue = [...availableConcurrent.fail, ...availableConcurrent.queue];
    availableConcurrent.fail = [];
    state.availableConcurrent.isStop = false;
    const count = availableSettings.taskConcurrencyLimit - state.availableConcurrent.active.length;
    for (let i = 0; i < count; i++) {
      processQueue(state, availableSettings.taskConcurrencyLimit, availableSettings.isStopByError);
    }
  }
  if (action.type === 'enqueueTask') {
    const availableSettings = useGigaStore.getState().availableSettings;
    const newTask: QueueItem = {
      task: action.task,
      resolve: action.resolve,
      reject: action.reject,
    };
    // 如果是重复任何立即返回 resolve 任务完成,这个任务不会计入任何的统计
    if (isRepeatAvailableTask(state.availableConcurrent.total, action.task)) {
      action.resolve(void 0);
      return;
    }
    state.availableConcurrent.total.push(newTask);
    state.availableConcurrent.queue.push(newTask);
    // console.log(action.taskConcurrencyLimit);
    processQueue(state, availableSettings.taskConcurrencyLimit, availableSettings.isStopByError);
  }
};

// @ts-expect-error 因为 immer 导致了 reducer 可以返回 undefiend
export const useGigaNotPersisStore = create(immer(redux(reducer, defaultState)));

// 初始化时尝试从 indexDB 中获取存储的 handle
const gigaRootDirectoryHandle = async () => {
  const db = await openDB();
  let rootDirectoryHandle: FileSystemDirectoryHandle | null = null;
  if (db) {
    const handle = await getStoredFileHandle(db, key);
    if (handle) {
      // 检查当前权限状态
      const permission = await handle.queryPermission({ mode: 'readwrite' });
      if (permission === 'granted') {
        // 权限有效，使用句柄
        rootDirectoryHandle = handle;
      } else {
        try {
          // 请求新权限
          const newPermission = await handle.requestPermission({ mode: 'readwrite' });
          if (newPermission === 'granted') {
            // 权限已授予
            rootDirectoryHandle = handle;
          } else {
            console.log('用户拒绝了权限');
          }
        } catch (error) {
          // 如果没有用户交互,那么这个时候请求新权限会报错
        }
      }
    }
  }
  if (!rootDirectoryHandle) {
    rootDirectoryHandle = await window
      .showDirectoryPicker({
        mode: 'readwrite',
      })
      .catch((error) => {
        console.log(error);
        return null;
      });
  }
  if (rootDirectoryHandle) {
    // 存储到 indexedDB 中
    await storeFileHandle(rootDirectoryHandle, key, db);
    useGigaNotPersisStore.dispatch({
      type: 'update',
      update(draftState) {
        draftState.gigaRootDirectoryHandle = rootDirectoryHandle;
      },
    });
    updateCateyoryTree(rootDirectoryHandle);
  }
};

gigaRootDirectoryHandle();

// 持久化处理
export const restoreAvaliableKey = name + '-giga-avaliable-task';
function handleBeforeUnload(event: BeforeUnloadEvent) {
  if (!restoreAvaliableKey) {
    return;
  }
  const availableConcurrent = useGigaNotPersisStore.getState().availableConcurrent;
  const restQueue = [...availableConcurrent.active, ...availableConcurrent.queue];
  // console.log(restQueue);
  const taskInfos = restQueue.map((task) => task.task.taskInfo);
  try {
    localStorage.setItem(restoreAvaliableKey, JSON.stringify(taskInfos));
  } catch (error) {
    toast.error(`localStorage 存储已经到达上限`);
  }
}
window.addEventListener('beforeunload', handleBeforeUnload);

// 每隔 3 秒记录正在处理和待处理的任务,避免浏览器崩溃后无法恢复
// const timmer = setInterval(handleBeforeUnload, 3000);
